#!/usr/bin/python2
# -*- coding: utf-8 -*-


import threading
import time
import logging
import os
import sys

from eventlet.queue import Empty

# from Queue import Queue
from eventlet import Queue,sleep

from ryuapp.lib.hedera.mock_dep import DepGraph,DepNode,Operation
from ryuapp.lib.hedera.updatewrapper import UpdateWrapper,UpdateTracker


class FlowStatus:
    def __init__(self):
        self.path = None
        self.dep_list = []


class SequentialExecutor():
    """
    Sequential Execution
    """
    def __init__(self, update_queue,install_queue,reply_queue):
        # super(Executor, self).__init__()
        assert isinstance(update_queue, Queue)
        assert isinstance(install_queue, Queue)
        assert isinstance(reply_queue, Queue)
        self.__update_queue = update_queue
        self.__install_queue = install_queue
        self.__reply_queue = reply_queue
        self.all_status = {}

        self.update_history = []

    def run(self):
        exec_count = 0

        while True:
            g = None

            print("exec_count", exec_count)

            try:
                g = self.__update_queue.get(timeout=20)
            except Empty:
                print("operation number=%d"%exec_count)
                print("update time array=%s"%list(u.tracker.duration for u in self.update_history))
                print("average time=%s" % (sum(u.tracker.duration for u in self.update_history) / len(self.update_history)))
                sys.stdout.flush()
                os._exit(0)

            assert isinstance(g, UpdateWrapper)

            update = g.update
            for pair,path in update.iteritems():
                self.all_status.setdefault(pair,FlowStatus())
                status = self.all_status[pair]
                status.dep_list = DepGraph.pair_construct(pair,status.path,path).nodes

            while True:
                for pair,status in self.all_status.iteritems():
                    for n in status.dep_list:
                        if n.status==DepNode.INIT and len(n.acquire)==0:
                            self.__exec(status, n)
                            exec_count+=1
                op = self.__reply_queue.get()
                self.__release_one(op)
                s = sum(len(status.dep_list) for status in self.all_status.itervalues())
                if s==0:
                    break

            for pair,path in update.iteritems():
                self.all_status[pair].path = path
                assert len(self.all_status[pair].dep_list)==0
            g.tracker.duration = time.time()-g.tracker.starttime
            self.update_history.append(g)
            print("updatetime=%f"%g.tracker.duration)



    def __exec(self,status, n):
        assert isinstance(status,FlowStatus)
        assert isinstance(n,DepNode)
        n.status = DepNode.WAIT
        self.__install_queue.put(n.op)
        print("exec",str(n.op))

    def __release_one(self, op):
        print("release", str(op), op)
        assert isinstance(op, Operation)
        pair = op.pair
        status = self.all_status[pair]
        u = None
        for i in status.dep_list:
            if i.op.eq(op):
                u=i
                break
        if u:
            self.__remove_dependency(u)
            status.dep_list.remove(u)
        else:
            raise Exception("error 2")


    def __remove_dependency(self,n):
        for nr in n.release:
            if n not in nr.acquire:
                raise Exception("not in nr.acquire")
            nr.acquire.remove(n)
        for na in n.acquire:
            if n not in na.release:
                raise Exception("not in na.release")
            na.release.remove(n)

    def __add_dependency(self, r, a):
        r.release.append(a)
        a.acquire.append(r)